/*
 * Created by JFormDesigner on Fri Feb 04 22:17:34 ART 2011
 */

package ar.com.visualAORE.view.panel;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.lang.reflect.Method;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Caret;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.Highlighter;
import javax.swing.text.Position;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.View;

import ar.com.visualAORE.controller.ReqInternalFrameController;
import ar.com.visualAORE.exceptions.SelectionNotFoundException;
import ar.com.visualAORE.model.Selection;
import ar.com.visualAORE.util.MapPainter;
import ar.com.visualAORE.util.UnderlineHighlightPainter;
import ar.com.visualAORE.view.ReqInternalFrame;
import ar.com.visualAORE.view.VisualDesktopFrame;
import ar.com.visualAORE.view.collapse.App;
import ar.com.visualAORE.view.collapse.CollapsibleEditorKit;
import ar.com.visualAORE.view.collapse.CollapsibleView;

/**
 * @author Brainrain
 */
public class TextViewPanel extends JPanel {
	VisualDesktopFrame vdf;
	ReqInternalFrame rif;
	ReqInternalFrameController controller;
	MapViewPanel mapView;
	Document doc;
	
	public TextViewPanel() {
		initComponents();
		textPaneTextView.setCaretPosition(0);
		textPaneTextView.setEditable(false);
		textPaneTextView.setContentType("text/html"); 
	}
	public TextViewPanel(VisualDesktopFrame vdf, ReqInternalFrame rif, ReqInternalFrameController controller, MapViewPanel mapView) {
		initComponents();
		this.vdf = vdf;
		this.rif = rif;
		this.controller = controller;
		this.mapView = mapView;
		textPaneTextView.setCaretPosition(0);
		textPaneTextView.setEditable(false);

		final SimpleAttributeSet attrs=new SimpleAttributeSet();
		textPaneTextView.setEditorKit(new CollapsibleEditorKit());
		textPaneTextView.setContentType("text/html"); 
		doc= this.textPaneTextView.getDocument();
		
		try {
			doc.insertString(doc.getLength(), "Par before area\n", new SimpleAttributeSet());
			doc.insertString(doc.getLength(), "Par after area\n", new SimpleAttributeSet());
			DefaultStyledDocument.ElementSpec[] specs = new DefaultStyledDocument.ElementSpec[10];
	            DefaultStyledDocument.ElementSpec closePar = new DefaultStyledDocument.ElementSpec(attrs, DefaultStyledDocument.ElementSpec.EndTagType);
	            specs[0]=closePar;

	            attrs.addAttribute(DefaultStyledDocument.ElementNameAttribute, CollapsibleEditorKit.COLLAPSIBLE_AREA_ELEMENT);
	            DefaultStyledDocument.ElementSpec areaStart = new DefaultStyledDocument.ElementSpec(attrs, DefaultStyledDocument.ElementSpec.StartTagType);
	            specs[1]=areaStart;
			
		} catch (BadLocationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		textPaneTextView.addMouseListener(new MouseAdapter() {
	        public void mouseClicked(MouseEvent e) {
	        	if(e.getButton()== MouseEvent.BUTTON1){
		            if (e.isControlDown()) {
		                int offs=textPaneTextView.viewToModel(e.getPoint());
		                CollapsibleView cv=getCollapsibleView(offs);
		                cv.setExpanded(!cv.isExpanded());
		                DefaultStyledDocument doc= (DefaultStyledDocument)textPaneTextView.getDocument();
		                try {
		                    doc.insertString(offs, "\n", new SimpleAttributeSet());
		                    doc.remove(offs,1);
		                } catch (BadLocationException e1) {
		                    e1.printStackTrace();  
		                }
		            }
		            else if(e.getButton()== MouseEvent.BUTTON3){
		            	System.out.println("BOTON DERECHO PRESIONADO");
		            }
	        	}
	        }
	    });
		
		 final JButton btnShow=new JButton("Add collapsible area");
	        btnShow.addActionListener(new ActionListener() {
	            public void actionPerformed(ActionEvent e) {
	                makeCollapsibleArea();
	            }
	        });
	        this.add(btnShow, BorderLayout.NORTH);
	}
	
	private void textPaneTextViewCaretUpdate(CaretEvent e) {
		// TODO add your code here
	}

	private void textPaneTextViewMouseReleased(MouseEvent e) {
		// TODO add your code here
		Caret seleccion = textPaneTextView.getCaret();
		if (seleccion.getDot() == seleccion.getMark())
		{
		   // No hay nada seleccionado
		}
		else if(vdf.getCurrentCocnern() != null) //Significa que hay un concern seleccionado para poder pintar
		{
			//	String textoTotal = textPane1.getText();
		    vdf.setPainter(new UnderlineHighlightPainter(vdf.getCurrentCocnern().getColor()));	
			System.out.println("ACTION: " + vdf.getAction());

		    try {
				if(seleccion.getDot() > seleccion.getMark()){
					//rif.getHighlighter().addHighlight(seleccion.getMark(), seleccion.getDot(), vdf.getPainter());
					//textPaneTextView.getHighlighter().addHighlight(seleccion.getMark(), seleccion.getDot(), vdf.getPainter());
					//Agrega una nueva seleccion
					if(vdf.getAction().equals("concern")){
						textPaneTextView.getHighlighter().addHighlight(seleccion.getMark(), seleccion.getDot(), new DefaultHighlighter.DefaultHighlightPainter(vdf.getCurrentCocnern().getColor()));
						this.controller.addSelection(new Selection(seleccion.getMark(), seleccion.getDot(), vdf.getCurrentCocnern(), textPaneTextView.getSelectedText().length(), getLineNumber(textPaneTextView, textPaneTextView.getCaretPosition()), textPaneTextView.getHighlighter().getHighlights().length-2), rif.getTitle());
					}
					else if(vdf.getAction().equals("eraser")){
						System.out.println("EN ERASER");
						//Busco la seleccion en el documento, a partir del dot
						try {
							Selection selection = this.controller.getSelection(seleccion.getDot(), rif.getTitle()); 
							this.controller.removeSelection(selection, rif.getTitle());
							
							// Remove any existing highlights for last word
							Highlighter.Highlight[] highlights = textPaneTextView.getHighlighter().getHighlights();
							for (int i = 0; i < highlights.length; i++) {
								System.out.println("Sel TAG NUMBER: " + selection.getHighlightTagNumber() + " i: " + i);
							  Highlighter.Highlight h = highlights[i];
							  if ((selection.getHighlightTagNumber()) == i) {
								  textPaneTextView.getHighlighter().removeHighlight(h);
								 // textPaneTextView.repaint();
								  rif.revalidate();
							  }
							}
						} catch (SelectionNotFoundException e1) {
							// TODO Auto-generated catch block
							e1.printStackTrace();
						}
					}
					
					//Para el blink
					try {
			            addBlink(seleccion.getMark(), seleccion.getDot(),vdf.getCurrentCocnern().getColor(), 300);
			        }
			        catch (BadLocationException ex) {
			            ex.printStackTrace();
			        }
				}
				else{
					if(vdf.getAction().equals("concern")){
						textPaneTextView.getHighlighter().addHighlight(seleccion.getDot(), seleccion.getMark(), new DefaultHighlighter.DefaultHighlightPainter(vdf.getCurrentCocnern().getColor()));
						this.controller.addSelection(new Selection(seleccion.getDot(), seleccion.getMark(), vdf.getCurrentCocnern(), textPaneTextView.getSelectedText().length(), getLineNumber(textPaneTextView, textPaneTextView.getCaretPosition()), textPaneTextView.getHighlighter().getHighlights().length - 2), rif.getTitle());
					}
					else if(vdf.getAction().equals("eraser")){
						System.out.println("EN ERASER");
						//Busco la seleccion en el documento, a partir del dot
						try {
							Selection selection = this.controller.getSelection(seleccion.getDot(), rif.getTitle()); 
							this.controller.removeSelection(selection, rif.getTitle());
							
							//EXTRAER este metodo
							// Remove any existing highlights for last word 
							Highlighter.Highlight[] highlights = textPaneTextView.getHighlighter().getHighlights();
							for (int i = 0; i < highlights.length; i++) {
								System.out.println("Sel TAG NUMBER: " + selection.getHighlightTagNumber() + " i: " + i);
							  Highlighter.Highlight h = highlights[i];
							  if ((selection.getHighlightTagNumber()) == i) {
								  textPaneTextView.getHighlighter().removeHighlight(h);
								 // textPaneTextView.repaint();
								  rif.revalidate();
							  }
							}
						} catch (SelectionNotFoundException e1) {
							// TODO Auto-generated catch block
							e1.printStackTrace();
						}
					}
					//Para el blink
					try {
			            addBlink(seleccion.getDot(), seleccion.getMark(),vdf.getCurrentCocnern().getColor(), 300);
			        }
			        catch (BadLocationException ex) {
			            ex.printStackTrace();
			        }
			        }
				getTextPane().setSelectionEnd(seleccion.getDot());
				getTextPane().setSelectionStart(seleccion.getMark());
				
		    } catch (BadLocationException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
		    }
		}

		
	}
	 public void addBlink(int startPos, int endPos, Color blinkColor, int blinkRate) throws BadLocationException {
		//  mapView.getTextPane().getHighlighter().addHighlight(startPos, endPos, new MapPainter(blinkColor, blinkRate, textPaneTextView));
	  }
	/**
	   * Return an int containing the wrapped line index at the given position
	   * @param component JTextPane
	   * @param int pos
	   * @return int
	   */
	  public int getLineNumber(JEditorPane component, int pos) 
	  {
	    int posLine;
	    int y = 0;

	    try
	    {
	      Rectangle caretCoords = component.modelToView(pos);
	      y = (int) caretCoords.getY();
	    }
	    catch (BadLocationException ex)
	    {
	    }

	    int lineHeight = component.getFontMetrics(component.getFont()).getHeight();
	    posLine = (y / lineHeight) + 1;
	    return posLine;
	  }
	  
	//FOR COLLAPSE	
		protected void insertSpecs(DefaultStyledDocument doc, int offset, DefaultStyledDocument.ElementSpec[] specs) {
			    try {
			//      doc.insert(0, specs);  method is protected so we have to
			      //extend document or use such a hack
			      Method m=DefaultStyledDocument.class.getDeclaredMethod("insert", new Class[] {int.class, DefaultStyledDocument.ElementSpec[].class});
			      m.setAccessible(true);
			      m.invoke(doc, new Object[] {offset, specs});
			  } catch (Exception e) {
			      e.printStackTrace();
			  }
		}
		protected CollapsibleView getCollapsibleView(int offset) {
		    View v=textPaneTextView.getUI().getRootView(this.textPaneTextView);
		    while( v!=null && v.getViewCount()>0) {
		        if (v instanceof CollapsibleView) {
		            return (CollapsibleView)v;
		        }
		        int i=v.getViewIndex(offset, Position.Bias.Forward);
		        if (i>=0 && i<v.getViewCount()) {
		            v=v.getView(i);
		        }
		        else {
		            break;
		        }
		    }
		
		    return null;
		}
		protected void makeCollapsibleArea() {
		        try {
		            int start=textPaneTextView.getSelectionStart();
		            int end=textPaneTextView.getSelectionEnd();
		            if (start==end) {
		                return;
		            }
		            clearCollapsibleArea();
		            if (start>end) {
		                int tmp=start;
		                start=end;
		                end=tmp;
		            }

		            DefaultStyledDocument doc=(DefaultStyledDocument)textPaneTextView.getDocument();
		            start=(doc).getParagraphElement(start).getStartOffset();
		            end=doc.getParagraphElement(end).getEndOffset();

		            ArrayList<DefaultStyledDocument.ElementSpec> specs=new ArrayList<DefaultStyledDocument.ElementSpec>();
		            DefaultStyledDocument.ElementSpec spec;
		            int offs=start;
		            while (offs<end) {
		                Element par=doc.getParagraphElement(offs);

		                spec=new DefaultStyledDocument.ElementSpec(par.getAttributes(), DefaultStyledDocument.ElementSpec.StartTagType);
		                specs.add(spec);
		                for (int i=0; i<par.getElementCount(); i++) {
		                    Element leaf=par.getElement(i);
		                    String text=doc.getText(leaf.getStartOffset(), leaf.getEndOffset()-leaf.getStartOffset());
		                    spec=new DefaultStyledDocument.ElementSpec(leaf.getAttributes(),DefaultStyledDocument.ElementSpec.ContentType, text.toCharArray(), 0, text.length());
		                    specs.add(spec);
		                }
		                spec=new DefaultStyledDocument.ElementSpec(par.getAttributes(), DefaultStyledDocument.ElementSpec.EndTagType);
		                specs.add(spec);

		                offs=par.getEndOffset();
		            }

		            doc.remove(start, end-start);
		            DefaultStyledDocument.ElementSpec[] specArray = new DefaultStyledDocument.ElementSpec[specs.size()+4];
		            DefaultStyledDocument.ElementSpec closePar = new DefaultStyledDocument.ElementSpec(new SimpleAttributeSet(), DefaultStyledDocument.ElementSpec.EndTagType);
		            specArray[0]=closePar;

		            SimpleAttributeSet attrs=new SimpleAttributeSet();
		            attrs.addAttribute(DefaultStyledDocument.ElementNameAttribute, CollapsibleEditorKit.COLLAPSIBLE_AREA_ELEMENT);
		            DefaultStyledDocument.ElementSpec areaStart = new DefaultStyledDocument.ElementSpec(attrs, DefaultStyledDocument.ElementSpec.StartTagType);
		            specArray[1]=areaStart;

		            for (int i=0; i<specs.size(); i++) {
		                specArray[i+2]=specs.get(i);
		            }

		            DefaultStyledDocument.ElementSpec areaEnd = new DefaultStyledDocument.ElementSpec(attrs, DefaultStyledDocument.ElementSpec.EndTagType);
		            specArray[specArray.length-2]=areaEnd;

		            DefaultStyledDocument.ElementSpec openPar = new DefaultStyledDocument.ElementSpec(attrs, DefaultStyledDocument.ElementSpec.StartTagType);
		            specArray[specArray.length-1]=openPar;

		            insertSpecs(doc, start, specArray);
		        } catch (BadLocationException e) {
		            e.printStackTrace();  
		        }
		    }

		protected void clearCollapsibleArea() {
	        try {
	            DefaultStyledDocument doc=(DefaultStyledDocument)this.textPaneTextView.getDocument();
	            Element root=doc.getDefaultRootElement();
	            for (int i=0; i<root.getElementCount(); i++) {
	                Element elem=root.getElement(i);
	                if (CollapsibleEditorKit.COLLAPSIBLE_AREA_ELEMENT.equals(elem.getName())) {
	                    ArrayList<DefaultStyledDocument.ElementSpec> specs=new ArrayList<DefaultStyledDocument.ElementSpec>();
	                    DefaultStyledDocument.ElementSpec spec;
	                    for (int j=0; j<elem.getElementCount(); j++) {
	                        Element par=elem.getElement(j);
	                        spec=new DefaultStyledDocument.ElementSpec(par.getAttributes(), DefaultStyledDocument.ElementSpec.StartTagType);
	                        specs.add(spec);
	                        for (int k=0; k<par.getElementCount(); k++) {
	                            Element leaf=par.getElement(k);
	                            String text=doc.getText(leaf.getStartOffset(), leaf.getEndOffset()-leaf.getStartOffset());
	                            spec=new DefaultStyledDocument.ElementSpec(leaf.getAttributes(),DefaultStyledDocument.ElementSpec.ContentType, text.toCharArray(), 0, text.length());
	                            specs.add(spec);
	                        }
	                        spec=new DefaultStyledDocument.ElementSpec(par.getAttributes(), DefaultStyledDocument.ElementSpec.EndTagType);
	                        specs.add(spec);
	                    }

	                    int start=elem.getStartOffset();
	                    doc.remove(start, elem.getEndOffset()-start);

	                    DefaultStyledDocument.ElementSpec[] specArray = new DefaultStyledDocument.ElementSpec[specs.size()+2];
	                    DefaultStyledDocument.ElementSpec closePar = new DefaultStyledDocument.ElementSpec(new SimpleAttributeSet(), DefaultStyledDocument.ElementSpec.EndTagType);
	                    specArray[0]=closePar;

	                    for (int j=0; j<specs.size(); j++) {
	                        specArray[j+1]=specs.get(j);
	                    }

	                    DefaultStyledDocument.ElementSpec openPar = new DefaultStyledDocument.ElementSpec(new SimpleAttributeSet(), DefaultStyledDocument.ElementSpec.StartTagType);
	                    specArray[specArray.length-1]=openPar;

	                    insertSpecs(doc, start, specArray);
	                    break;
	                }
	            }
	        } catch (BadLocationException e) {
	            e.printStackTrace();  
	        }
	    }
	  
	/**
	 * Devuelve el JTextPane
	 * @return
	 */
	public JEditorPane getTextPane(){
		return this.textPaneTextView;
	}
	public JScrollPane getScrollPane(){
		return this.scrollPane1;
	}
	private void initComponents() {
		// JFormDesigner - Component initialization - DO NOT MODIFY  //GEN-BEGIN:initComponents
		scrollPane1 = new JScrollPane();
		textPaneTextView = new JEditorPane();

		//======== this ========
		setLayout(new BorderLayout());

		//======== scrollPane1 ========
		{

			//---- textPaneTextView ----
			textPaneTextView.addCaretListener(new CaretListener() {
				public void caretUpdate(CaretEvent e) {
					textPaneTextViewCaretUpdate(e);
				}
			});
			textPaneTextView.addMouseListener(new MouseAdapter() {
				@Override
				public void mouseReleased(MouseEvent e) {
					textPaneTextViewMouseReleased(e);
				}
			});
			scrollPane1.setViewportView(textPaneTextView);
		}
		add(scrollPane1, BorderLayout.CENTER);
		// JFormDesigner - End of component initialization  //GEN-END:initComponents
	}

	// JFormDesigner - Variables declaration - DO NOT MODIFY  //GEN-BEGIN:variables
	private JScrollPane scrollPane1;
	private JEditorPane textPaneTextView;
	// JFormDesigner - End of variables declaration  //GEN-END:variables
}
